package com.ikingtech.datav.config;

import cn.hutool.core.text.CharSequenceUtil;
import com.fasterxml.jackson.core.type.TypeReference;
import com.ikingtech.datav.exception.ProjectFileExceptionInfo;
import com.ikingtech.datav.model.constant.FileConstant;
import com.ikingtech.datav.model.entity.SystemConfigDO;
import com.ikingtech.datav.service.SystemConfigService;
import com.ikingtech.framework.sdk.context.constant.SecurityConstants;
import com.ikingtech.framework.sdk.context.security.Identity;
import com.ikingtech.framework.sdk.context.security.Me;
import com.ikingtech.framework.sdk.core.response.R;
import com.ikingtech.framework.sdk.enums.system.role.DataScopeTypeEnum;
import com.ikingtech.framework.sdk.role.api.RoleApi;
import com.ikingtech.framework.sdk.role.model.RoleDTO;
import com.ikingtech.framework.sdk.role.model.RoleMenuUpdateParamDTO;
import com.ikingtech.framework.sdk.utils.Tools;
import com.ikingtech.platform.service.oss.controller.OssFileController;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.stereotype.Component;
import org.springframework.util.FileCopyUtils;

import java.io.IOException;
import java.io.InputStream;
import java.util.*;

/**
 * created on 2024-03-22 13:46
 * 准备资源
 *
 * @author wub
 */
@Slf4j
@Component
@RequiredArgsConstructor
public class PrepareResources implements ApplicationListener<ApplicationReadyEvent> {

    private final OssFileController ossApi;

    private final SystemConfigService systemConfigService;

    private final RoleApi roleApi;

    @Value("${datav.fileUrl}")
    public String fileUrl;

    @Value("${datav.originalRole}")
    public String originalRole;

    @Override
    public void onApplicationEvent(@NotNull ApplicationReadyEvent event) {

        List<SystemConfigDO> datavConfig = systemConfigService.getInfoByType(FileConstant.DATA_V);
        if (datavConfig.isEmpty()) {
            SystemConfigDO systemConfigDO = new SystemConfigDO();
            HashMap<String, Object> map = new HashMap<>(1);
            map.put("fileUrl", fileUrl);
            systemConfigDO.setType(FileConstant.DATA_V);
            systemConfigDO.setProperties(Tools.Json.toJsonStr(map));
            systemConfigService.save(systemConfigDO);
            log.info("写入fileUrl资源预览地址：{}", fileUrl);
        } else {
            SystemConfigDO systemConfig = datavConfig.get(0);
            HashMap<String, Object> map = Tools.Json.toBean(systemConfig.getProperties(), new TypeReference<>() {});
            FileConstant.FILE_CDN_URL = map.getOrDefault("fileUrl", CharSequenceUtil.EMPTY).toString();
        }
        //给一个初始化的角色
        this.roleMenu();

        log.info("正在检查资源包...");
        R<Boolean> exits = ossApi.existsObject(FileConstant.LOGO_SOURCE);
        if (!exits.isSuccess() ) {
            log.info(ProjectFileExceptionInfo.FILE_SERVICE_ERROR.message());
            return;
        }
        if (exits.getData()) {
            log.info("资源包已初始化");
            return;
        }
        log.info("开始初始化资源..");
        this.proceed();
        log.info("资源初始化完成!!!");
    }

    private void roleMenu() {
        List<RoleDTO> data = roleApi.all().getData();
        if (data.isEmpty() && Boolean.TRUE.toString().equals(originalRole)) {
            Identity identity = Identity.admin();
            identity.setDomainCode("TENANT");
            identity.setTenantCode(SecurityConstants.DEFAULT_TENANT_CODE);
            Me.set(identity);
            RoleDTO roleDTO = new RoleDTO();
            roleDTO.setName(FileConstant.DATA_V);
            roleDTO.setDataScopeType(DataScopeTypeEnum.ALL);
            roleDTO.setSortOrder(0);
            R<String> add = roleApi.add(roleDTO);
            RoleMenuUpdateParamDTO roleMenuUpdateParamDTO = new RoleMenuUpdateParamDTO();
            roleMenuUpdateParamDTO.setRoleId(add.getData());
            roleMenuUpdateParamDTO.setMenuIds(Collections.singletonList(SecurityConstants.DEFAULT_TENANT_CODE));
            roleApi.updateRoleMenu(roleMenuUpdateParamDTO);
        }
    }

    private void proceed() {
        try {
            HashMap<String, String> map = staticResourceMap();
            map.forEach((k, v) -> {
                Map<String, byte[]> stringMap = this.readDirectoryAsMap(k);
                stringMap.forEach((fileName, bytes) -> {
                    if (Tools.Str.isNotBlank(fileName)) {
                        ossApi.uploadByte(fileName, v, bytes, true, true);
                    }
                });
            });
        } catch (Exception e) {
            log.error("资源初始化失败,异常信息【{}】", e.getMessage(), e);
        }
    }

    private static @NotNull HashMap<String, String> staticResourceMap() {
        HashMap<String, String> map = new LinkedHashMap<>();
        map.put(FileConstant.LOCAL_SOURCE_COM_PICTURE, FileConstant.BUCKET_SOURCE_COM_PICTURE);
        map.put(FileConstant.LOCAL_SOURCE_IMAGE, FileConstant.BUCKET_SOURCE_RESOURCE_IMAGE);
        map.put(FileConstant.LOCAL_SOURCE_MAP_JSON, FileConstant.BUCKET_SOURCE_MAP_JSON);
        map.put(FileConstant.LOCAL_SOURCE_SYSTEM, FileConstant.BUCKET_SOURCE_SYSTEM);
        map.put(FileConstant.LOCAL_SOURCE_TEMPLATE, FileConstant.BUCKET_SOURCE_TEMPLATE);
        map.put(FileConstant.LOCAL_SOURCE_FILE, FileConstant.FILE_BASE_URL);
        return map;
    }

    private Map<String, byte[]> readDirectoryAsMap(String directoryPath) {
        Map<String, byte[]> fileDataMap = new HashMap<>(4);
        try {
            PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
            Resource[] resources = resolver.getResources("classpath*:" + directoryPath + "/*.*");
            for (Resource resource : resources) {
                InputStream inputStream = resource.getInputStream();
                byte[] fileBytes = FileCopyUtils.copyToByteArray(inputStream);
                fileDataMap.put(resource.getFilename(), fileBytes);
            }
        } catch (IOException e) {
            log.error("读取目录失败, 异常信息【{}】", e.getMessage(), e);
        }
        return fileDataMap;
    }
}
